package com.geekhole.demo.v1.application;

import com.geekhole.demo.application.UserApplication;
import com.geekhole.demo.domain.CreateAndEnableUserContext;
import com.geekhole.demo.domain.ModifyUserNameContext;
import com.geekhole.demo.domain.User;
import com.geekhole.demo.domain.UserNotFoundException;
import com.geekhole.demo.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserV1Application implements UserApplication {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserV1Application.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(readOnly = false)
    public void createAndEnableUser(CreateAndEnableUserContext context){
        try {
            // 1. 生成 聚合根
            User user = User.create(context.getName(), context.getAge());

            // 2. 执行业务访问
            user.enable();

            // 3. 保存聚合根
            this.userRepository.save(user);

            // 4. 发布领域事件
            user.foreachEvent(this.eventPublisher::publishEvent);

            // 5. 清理领域事件
            user.clearEvents();

            LOGGER.info("success to handle createAndEnableUser and sync {} to DB", user);
        }catch (Exception e){
            LOGGER.error("failed to handle createAndEnableUser", e);
            if (e instanceof RuntimeException){
                throw (RuntimeException) e;
            }
            throw new RuntimeException(e);
        }

    }

    @Override
    @Transactional(readOnly = false)
    public void modifyUserName(ModifyUserNameContext context){
        try {

            // 1. 加载聚合根
            User user = this.userRepository.getById(context.getUserId());

            // 2. 验证聚合根
            if (user == null){
                throw new UserNotFoundException(context.getUserId());
            }

            // 3. 调用聚合根方法
            user.modifyUserName(context.getNewName());

            // 4. 保持对象
            this.userRepository.save(user);

            // 5. 发布领域事件
            user.foreachEvent(this.eventPublisher::publishEvent);

            // 6. 清理领域事件
            user.clearEvents();

            LOGGER.info("success to handle modifyUserName and sync {} to DB", user);
        }catch (Exception e){
            LOGGER.error("failed to handle modifyUserName", e);
            if (e instanceof RuntimeException){
                throw (RuntimeException) e;
            }
            throw new RuntimeException(e);
        }

    }

}
